// std::invoke 详解
// std::invoke 是C++17引入的一个函数模板，它提供了一种统一的方式来调用各种可调用对象，无论是普通函数、成员函数、函数对象还是Lambda表达式。

// 基本语法
template <class F, class... Args>
invoke_result_t<F, Args...> invoke(F &&f, Args &&...args);

// 主要用途
// std::invoke 的核心价值在于它提供了一个统一的接口来调用不同类型的可调用对象，特别是解决了成员函数调用的特殊语法问题。
// 1. 统一调用语法
// 普通函数
int add(int a, int b) { return a + b; }

// 成员函数
class Calculator
{
public:
    int multiply(int a, int b) { return a * b; }
};

// 函数对象
struct Divider
{
    int operator()(int a, int b) { return a / b; }
};

// 使用std::invoke统一调用
Calculator calc;
Divider div;

int result1 = std::invoke(add, 10, 20);                         // 调用普通函数
int result2 = std::invoke(&Calculator::multiply, calc, 10, 20); // 调用成员函数
int result3 = std::invoke(div, 20, 5);                          // 调用函数对象

// 2. 在泛型代码中处理各种可调用对象
template <typename Callable, typename... Args>
auto call_and_log(Callable &&func, Args &&...args)
{
    std::cout << "Calling function..." << std::endl;
    auto result = std::invoke(std::forward<Callable>(func),
                              std::forward<Args>(args)...);
    std::cout << "Function returned." << std::endl;
    return result;
}

// 可以用于任何可调用对象
call_and_log(add, 5, 3);
call_and_log(&Calculator::multiply, calc, 4, 7);
call_and_log([](int x)
             { return x * x; }, 6);

// 调用成员函数的特殊处理
// std::invoke 对成员函数指针有特殊处理：
class Widget
{
public:
    void process() { std::cout << "Processing..." << std::endl; }
    int getValue() const { return 42; }
};

Widget w;
Widget *pw = &w;

// 以下调用都是等效的
std::invoke(&Widget::process, w);           // 使用对象
std::invoke(&Widget::process, pw);          // 使用指针
std::invoke(&Widget::process, std::ref(w)); // 使用引用包装器

// 智能指针也可以工作
auto spw = std::make_shared<Widget>();
std::invoke(&Widget::process, spw);

// 数据成员指针
// std::invoke 也支持调用数据成员指针：
struct Point
{
    int x = 0;
    int y = 0;
};

Point p{10, 20};
int x = std::invoke(&Point::x, p); // 获取p.x的值，结果为10

// 也可以修改成员
std::invoke(&Point::y, p) = 30; // 设置p.y = 30

// 实现原理
// std::invoke 的实现基于SFINAE和完美转发，大致如下：
// 简化版实现
template <typename F, typename... Args>
auto invoke(F &&f, Args &&...args)
    -> decltype(std::forward<F>(f)(std::forward<Args>(args)...))
{
    return std::forward<F>(f)(std::forward<Args>(args)...);
}

// 成员函数指针特化
template <typename R, typename C, typename Obj, typename... Args>
auto invoke(R (C::*f)(Args...), Obj &&obj, Args &&...args)
    -> decltype((std::forward<Obj>(obj).*f)(std::forward<Args>(args)...))
{
    return (std::forward<Obj>(obj).*f)(std::forward<Args>(args)...);
}

// 数据成员指针特化
template <typename M, typename C, typename Obj>
auto invoke(M C::*m, Obj &&obj)
    -> decltype(std::forward<Obj>(obj).*m)
{
    return std::forward<Obj>(obj).*m;
}

// std::invoke 是C++17中的一个重要工具，它简化了泛型编程中对各种可调用对象的处理，使代码更加统一和优雅。在编写高级泛型库和元编程时，它是一个非常有价值的工具。
